/*
 ------------------------------------------------------------------------------
 Copyright (C) 2006-2007 Team Blur.

 This file is part of the Quantum Engine source code.

 The Quantum Engine source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quantum Engine source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quantum Engine source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


#ifndef __MATH_MATH_H__
#define __MATH_MATH_H__


class	odVec2;
class	odVec3;
class	odVec4;
class	odVec5;
class	odAngles;
class	odQuat;
class	odMat3;
class	odMat4;
class	odJointMat;
class	odBounds;
class	odPlane;

#ifndef M_E
#define M_E							2.71828182845904523536f
#endif

#ifndef M_PI
#define M_PI						3.14159265358979323846f
#endif

#define M_PI_TWO					6.28318530717958647692f
#define M_PI_HALF					1.57079632679489661923f
#define M_SQRT_TWO					1.41421356237309504880f
#define M_SQRT_HALF					0.70710678118654752440f
#define M_EPSILON					1.192092896e-07f
#define M_INFINITY					1e30f

#define DEG2RAD(a)					(((a) * M_PI) / 180.0f)
#define RAD2DEG(a)					(((a) * 180.0f) / M_PI)

#define ANGLE2BYTE(a)				(M_FtolFast((a) * 256.0f/360.0f) & 255)
#define BYTE2ANGLE(a)				((a) * (360.0f/256.0f))

#define	ANGLE2SHORT(a)				(M_FtolFast((a) * 65536.0f/360.0f) & 65535)
#define	SHORT2ANGLE(a)				((a) * (360.0f/65536.0f))

#define SEC2MS(t)					(M_FtolFast((t) * 1000.0f))
#define MS2SEC(t)					((t) * 0.001f)

#define Sign(x)						(((x) > 0) ? 1 : ((x) < 0) ? -1 : 0)

#define Min(x, y)					(((x) < (y)) ? (x) : (y))
#define Max(x, y)					(((x) > (y)) ? (x) : (y))

extern uint			m_randSeed;


INLINE void M_RandSeed (uint seed){

	m_randSeed = seed;
}

INLINE int M_RandInt (void){

	return (((m_randSeed = m_randSeed * 214013 + 2531011) >> 16) & 0x7FFF);
}

INLINE float M_RandFloat (void){

	return (M_RandInt() * (1.0f/0x7FFF));
}

INLINE float M_CRandFloat (void){

	return (M_RandInt() * (2.0f/0x7FFF) - 1.0f);
}

INLINE float M_Sin (float f){

	return sinf(f);
}

INLINE float M_Cos (float f){

	return cosf(f);
}

INLINE void M_SinCos (float f, float *s, float *c){

#ifdef _WIN32_ASM

	__asm {
		fld		f
		mov		ecx, s
		mov		edx, c
		fsincos
		fstp	dword ptr[edx]
		fstp	dword ptr[ecx]
	}

#else

	*s = sinf(f);
	*c = cosf(f);

#endif
}

INLINE float M_Tan (float f){

	return tanf(f);
}

INLINE float M_ASin (float f){

	return asinf(f);
}

INLINE float M_ACos (float f){

	return acosf(f);
}

INLINE float M_ATan (float f){

	return atanf(f);
}

INLINE float M_ATan2 (float y, float x){

	return atan2f(y, x);
}

INLINE float M_Log (float f){

	return logf(f);
}

INLINE float M_Exp (float f){

	return expf(f);
}

INLINE float M_Pow (float x, float y){

	return powf(x, y);
}

INLINE float M_Sqrt (float f){

	return sqrtf(f);
}

INLINE float M_RSqrt (float f){

	float	r;
	int		i;

	i = *(int *)&f;
	i = 0x5F3759DF - (i >> 1);
	r = *(float *)&i;
	r = r * (1.5f - ((f * 0.5f) * r * r));

	return r;
}

INLINE float M_Floor (float f){

	return floorf(f);
}

INLINE float M_Ceil (float f){

	return ceilf(f);
}

INLINE float M_Frac (float f){

	return f - floorf(f);
}

INLINE float M_RInt (float f){

	return floorf(f + 0.5f);
}

INLINE int M_Abs (int i){

	int		mask;

	mask = i >> 31;

	return ((i ^ mask) - mask);
}

INLINE float M_Fabs (float f){

	*(int *)&f &= 0x7FFFFFFF;

	return f;
}

INLINE bool M_IsPowerOfTwo (int i){

	return (i > 0 && !(i & (i - 1)));
}

INLINE int M_FloorPowerOfTwo (int i){

	i |= (i >> 1);
	i |= (i >> 2);
	i |= (i >> 4);
	i |= (i >> 8);
	i |= (i >> 16);

	i -= (i >> 1);

	return i + (i == 0);
}

INLINE int M_CeilPowerOfTwo (int i){

	i--;
	i |= (i >> 1);
	i |= (i >> 2);
	i |= (i >> 4);
	i |= (i >> 8);
	i |= (i >> 16);
	i++;

	return i + (i == 0);
}

INLINE int M_Ftol (float f){

#ifdef _WIN32_ASM

	float	half;
	int		i;

	__asm {
		mov		edx, f
		and		edx, 80000000h
		or		edx, 3EFFFFDEh
		mov		half, edx
		fld		f
		fsub	half
		fistp	i
	}

	return i;

#else

	return (int)f;

#endif
}

INLINE int M_FtolFast (float f){

#ifdef _WIN32_ASM

	int		i;

	__asm {
		fld		f
		fistp	i
	}

	return i;

#else

	return (int)f;

#endif
}

INLINE char M_ClampChar (int value){

	if (value < -128)
		return -128;

	if (value > 127)
		return 127;

	return value;
}

INLINE byte M_ClampByte (int value){

	if (value < 0)
		return 0;

	if (value > 255)
		return 255;

	return value;
}

INLINE short M_ClampShort (int value){

	if (value < -32768)
		return -32768;

	if (value > 32767)
		return 32767;

	return value;
}

INLINE int M_ClampLong (int value, int min, int max){

	if (value < min)
		return min;

	if (value > max)
		return max;

	return value;
}

INLINE float M_ClampFloat (float value, float min, float max){

	if (value < min)
		return min;

	if (value > max)
		return max;

	return value;
}


void			M_NormalToBytes (const odVec3 &normal, byte bytes[2]);
void			M_BytesToNormal (const byte bytes[2], odVec3 &normal);


#endif	// __MATH_MATH_H__
